package com.huluobo.base.mvvm

import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.SPUtils
import com.huluobo.base.net.Const
import com.huluobo.base.net.Res
import com.huluobo.base.net.Res2
import kotlinx.coroutines.launch
import java.lang.RuntimeException

/**
 *  Created by LC on 2024/12/13.
 */
open class BaseViewModel : ViewModel() {
    //通用的失败的LiveData
    val onFailed by lazy { MutableLiveData<Throwable>() }

    fun executeNetwork(
        //suspend 挂起方法,也就是apiService中的请求方法,() -> 代表当前参数是一个方法,Res代表当前方法的返回值
        s: suspend () -> Res,
        //成功的LiveData,会把s的返回值中的values添加到success中
        success: (String) -> Unit,
        //失败的LiveData,会把失败的信息(Throwable)直接传递到通用的onFailed的postValue方法中
        failed: (Throwable) -> Unit = onFailed::postValue,
        okCode: Int = 200
    ) {
        viewModelScope.launch {
            try {
                //发起网络请求,invoke就是调用的意思,当前就是调用一次挂起方法,让他产生返回值res
                val res = s.invoke()
                SPUtils.getInstance().put(Const.PARAM_HOME, res.home)
                Log.i("TagA", "res:$res")
                if (res.statuesCode.toInt() == okCode) {
                    //如果网络请求成功为200,就把通用的Res中的values给成功的LiveData赋值
                    success(res.values)
                } else {
                    //如果失败,则把错误信息包一层Exception,存放到失败的LiveData中
                    failed(RuntimeException(res.msg))
                }

            } catch (e: Exception) {
                failed(e)
            }
        }
    }

    fun <T> executeNetwork2(
        //suspend 挂起方法,也就是apiService中的请求方法,() -> 代表当前参数是一个方法,Res代表当前方法的返回值
        s: suspend () -> Res2<T>,
        //成功的LiveData,会把s的返回值中的values添加到success中
        success: (T) -> Unit,
        //失败的LiveData,会把失败的信息(Throwable)直接传递到通用的onFailed的postValue方法中
        failed: (Throwable) -> Unit = onFailed::postValue,
        okCode: Int = 200
    ) {
        viewModelScope.launch {
            try {
                val res2 = s.invoke()
                if (res2.code == okCode) {
                    success(res2.data)
                } else {
                    failed(RuntimeException(res2.message))
                }

            } catch (e: Exception) {
                failed(e)
            }
        }
    }

    fun <D> executeDb(
        s: suspend () -> D,
        complete: (D) -> Unit,
        failed: (Throwable) -> Unit = onFailed::postValue
    ) {
        viewModelScope.launch {
            try {
                complete(s.invoke())
            } catch (e: Exception) {
                failed(e)
            }
        }
    }
}